#include "cybertron/bridge/CybertronBridgeTaskBase.hpp"
#include "cybertron/core/Log.hpp"
#include <thread>


CYBERTRON_BEGIN

CybertronBridgeTaskBase::CybertronBridgeTaskBase()
{
	mState = STATE_IDLE;
	mNoPause = false;
}

CybertronBridgeTaskBase::~CybertronBridgeTaskBase()
{
	mState = STATE_END;
}

void CybertronBridgeTaskBase::reset()
{
	logEvent("Reset Task %s as required", name().c_str());
	switch (mState)
	{
	case STATE_END:
		break;
	default:
		mState = STATE_RESET;
		break;
	}
}

void CybertronBridgeTaskBase::fromBridgePlay()
{
	switch (mState)
	{
	case STATE_PAUSE:
		mState = STATE_RUNNING;
		break;
	default:
		break;
	}
}

void CybertronBridgeTaskBase::fromBridgePause()
{
	switch (mState)
	{
	case STATE_RUNNING:
	case STATE_RESET:
		mState = STATE_PAUSE;
		break;
	default:
		break;
	}
}

void CybertronBridgeTaskBase::fromBridgeReset()
{
	switch (mState)
	{
	case STATE_END:
		break;
	default:
		mState = STATE_RESET;
		break;
	}
}

void CybertronBridgeTaskBase::fromBridgeEnd()
{
	mState = STATE_END;
}

void CybertronBridgeTaskBase::tryStartTask()
{
	mState = STATE_RUNNING;
	mFrame = 0;
	logSilent("Bridge task %s starting...", name().c_str());
	while (!onStart())
	{
		switch (mState)
		{
		case STATE_END:
			return;
		default:
			break;
		}
		logSilent("Bridge task %s start failed... try again 1 sec later", name().c_str());
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	logSilent("Bridge task %s start success", name().c_str());
}

void CybertronBridgeTaskBase::run(float speed)
{
	std::chrono::high_resolution_clock::time_point beginTS;
	std::chrono::high_resolution_clock::time_point endTS;
	std::chrono::nanoseconds frameCostNS;
	tryStartTask();
	while (1)
	{
		while (mState != STATE_RUNNING)
		{
			switch (mState)
			{
			case STATE_IDLE:
				throw std::runtime_error("Bridge task running in idle state");
			case STATE_END:
				onEnd();
				logEvent("Bridge task %s ended", name().c_str());
				return;
			case STATE_RESET:
				logEvent("Bridge task %s reset", name().c_str());
				onEnd();
				std::this_thread::sleep_for(std::chrono::milliseconds(100));
				tryStartTask();
				break;
			case STATE_PAUSE:
			default:
				if(!mNoPause)
					std::this_thread::sleep_for(std::chrono::milliseconds(500));
				break;
			}
		}
		std::chrono::milliseconds frameDurationMS(1000 / (int)((float)mHz *speed));

		beginTS = std::chrono::high_resolution_clock::now();
		if (getSwitch())
		{
			mTaskCompleteCounter += onFrame(mFrame);
			++mFrame;
		}
		endTS = std::chrono::high_resolution_clock::now();
		frameCostNS = endTS - beginTS;
		std::chrono::milliseconds frameCostMS((frameCostNS.count() / 1000000));
		if (frameCostMS.count() < frameDurationMS.count())
		{
			std::this_thread::sleep_for(std::chrono::milliseconds(frameDurationMS.count() - frameCostMS.count()));
		}
		else if (frameCostMS.count() > frameDurationMS.count())
		{
			logWarning("Bridge task %s delayed %d MS",  name().c_str(), frameCostMS.count() - frameDurationMS.count());
		}
	}
}

CYBERTRON_END